#include "StdAfx.h"
#include "G711Codec.h"

static bool g_bInitG711 = false;

static short alawTab[256] , ulawTab[256];
static unsigned char seg_tab[256];

inline unsigned char val_seg   (unsigned char  val) 
{ 
	int   r   =   0; 
	if   (val   &   0xf0) 
	{ 
		val   >>=   4; 
		r   +=   4; 
	} 
	if   (val   &   0x0c) 
	{ 
		val   >>=   2; 
		r   +=   2; 
	} 
	if   (val   &   0x02) 
		r   +=   1; 
	return   r; 
} 

inline unsigned   char  linear2alaw   (int   pcm_val) 
{ 
	int   mask; 
	int   seg; 
	unsigned   char   aval; 
	if   (pcm_val   >=   0) 
	{ 
		mask   =   0xD5; 
	}   
	else 
	{ 
		mask   =   0x55; 
		pcm_val   =   -pcm_val; 
	} 
	if   (pcm_val   <   256) 
		aval   =   pcm_val   >>   4; 
	else 
	{ 
		seg   =   seg_tab[   (pcm_val >> 7)]; 
		aval   =   (seg   <<   4) | ((pcm_val   >>   (seg   +   3))   &   0x0f); 
	} 
	return   aval   ^   mask; 
} 

inline unsigned   char linear2ulaw   (int   pcm_val)
{ 
	int   mask; 
	int   seg; 
	unsigned   char   uval; 

	if   (pcm_val   <   0) 
	{ 
		pcm_val   =   0x84   -   pcm_val; 
		mask   =   0x7f; 
	}   
	else 
	{ 
		pcm_val   +=   0x84; 
		mask   =   0xff; 
	} 
	if   (pcm_val   >   0x7fff) 
		pcm_val   =   0x7fff; 

	seg   =   seg_tab[(pcm_val >> 7)]; 

	uval   =   (seg   <<   4)  |   ((pcm_val   >>   (seg   +   3))   &   0x0f); 
	return   uval   ^   mask; 
} 



inline int alaw_to_s16   (unsigned   a_val) 
{ 
	int   t; 
	int   seg; 

	a_val   ^=   0x55; 
	t   =   a_val   &   0x7f; 
	if   (t   <   16) 
		t   =   (t   <<   4)   +   8; 
	else 
	{ 
		seg   =   (t   >>   4)   &   0x07; 
		t   =   ((t   &   0x0f)   <<   4)   +   0x108; 
		t   <<=   seg   -   1; 
	} 
	return   ((a_val   &   0x80)   ?   t   :   -t); 
} 

inline int ulaw_to_s16   (unsigned   u_val) 
{ 
	int   t; 

	u_val   =   ~u_val; 

	t   =   ((u_val   &   0x0f)   <<   3)   +   0x84; 
	t   <<=   (u_val   &   0x70)   >>   4; 

	return   ((u_val   &   0x80)   ?   (0x84   -   t)   :   (t   -   0x84)); 
} 

void InitG711()
{
	if(seg_tab[255] == 0)
	{
		for (unsigned i = 0 ; i < 256 ; ++i)
		{
			alawTab[i] = (short)alaw_to_s16(i);
			ulawTab[i] = (short)ulaw_to_s16(i);
			seg_tab[i] = val_seg(i);
		}
	}
}


G711Codec::G711Codec(void)
{
	if( !g_bInitG711 )
	{
		g_bInitG711 = true;
		InitG711();
	}
}

G711Codec::~G711Codec(void)
{
}




void G711Codec::EncodeAlaw(unsigned char * dst , short * pcm , unsigned count)
{
	for (unsigned i = 0 ; i < count ; ++i)
	{
		dst[i] = linear2alaw(pcm[i]);
	}
}

void G711Codec::EncodeUlaw(unsigned char * dst , short * pcm , unsigned count)
{
	for (unsigned i = 0 ; i < count ; ++i)
	{
		dst[i] = linear2ulaw(pcm[i]);
	}
}


void G711Codec::DecodeAlaw(short * dst , unsigned char * src , unsigned count)
{
	for(unsigned i = 0 ; i < count ; ++i)
	{
		dst[i] = alawTab[src[i]];
	}
}

void G711Codec::DecodeUlaw(short * dst , unsigned char * src , unsigned count)
{
	for(unsigned i = 0 ; i < count ; ++i)
	{
		dst[i] = ulawTab[src[i]];
	}
}